package com.eva.service.cms;

import com.eva.dao.cms.CategoryMapper;
import com.eva.dao.cms.model.CmsCategory;
import com.eva.framework.mp.service.BaseService;
import com.eva.service.cms.vo.BaseCmsCategoryNode;
import org.springframework.beans.BeanUtils;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class CmsCategoryService extends BaseService<CmsCategory, CategoryMapper> {

    public CmsCategoryService(CategoryMapper mapper, Environment environment) {
        super(mapper, environment);
    }

    /**
     * 根据唯一标识查询
     *
     * @param uid 唯一标识
     * @return CmsCategory
     */
    public CmsCategory findByUid (String uid) {
        return this.findOne(CmsCategory.builder().uid(uid).build());
    }

    /**
     * 转换为树
     *
     * @param categories 栏目列表
     * @return List<CategoryNodeVO>
     */
    public <R extends BaseCmsCategoryNode> List<R> transferToTree (List<? extends CmsCategory> categories, Class<R> clazz) {
        try {
            List<R> categoryNodes = new ArrayList<>();
            // 添加根栏目
            for (CmsCategory category : categories) {
                if (category.getParentId() != null) {
                    continue;
                }
                R rootNode = clazz.getDeclaredConstructor().newInstance();
                BeanUtils.copyProperties(category, rootNode);
                rootNode.setChildren(new ArrayList<>());
                categoryNodes.add(rootNode);
            }
            // 移除根栏目
            categories.removeIf(category -> category.getParentId() == null);
            // 循环为根栏目添加子栏目
            for (R child : categoryNodes) {
                this.fillChildren(child, categories, clazz);
            }
            return categoryNodes;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 填充子栏目
     *
     * @param <M> 栏目类型
     * @param <N> 栏目节点类型
     * @param parent 父栏目
     * @param categories 未添加到父栏目中的子栏目列表
     * @param clazz 栏目节点类型
     */
    private <N extends BaseCmsCategoryNode, M extends CmsCategory> void fillChildren(N parent, List<M> categories, Class<N> clazz) {
        try {
            if (categories.size() == 0) {
                return;
            }
            List<N> parentChildren = (ArrayList<N>) parent.getChildren();
            // 记录已添加的子栏目
            List<M> addedCategories = new ArrayList<>();
            // 循环子栏目，逐一添加到父栏目中
            for (M category : categories) {
                if (!parent.getId().equals(category.getParentId())) {
                    continue;
                }
                // 构建子栏目节点对象
                N child = clazz.getDeclaredConstructor().newInstance();
                BeanUtils.copyProperties(category, child);
                child.setChildren(new ArrayList<N>());
                parentChildren.add(child);
                // 记录到已添加的栏目列表中
                addedCategories.add(category);
            }
            // 移除已添加的栏目
            categories.removeIf(addedCategories::contains);
            // 递归为子栏目添加子栏目
            for (BaseCmsCategoryNode child : parent.getChildren()) {
                this.fillChildren((N) child, categories, clazz);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
